#ifndef TB_REFELCTION_SIGNATURE_HPP__
#define TB_REFELCTION_SIGNATURE_HPP__

#include "tbcore/base/basic_types.hpp"

#include <boost/mpl/apply.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/vector.hpp>

TB_NAMESPACE_BEGIN

class Signature {
public:
  bool IsSame(const Signature& r) const {
    if (GetParamCount() == r.GetParamCount() && GetRetType() == r.GetRetType()) {
      for (uint32 index = 0; index < GetParamCount(); ++index) {
        if (GetParamType(index) != r.GetParamType(index)) {
          return false;
        }
      }
      return true;
    }
    return false;
  }

  virtual uint32 GetParamCount() const = 0;

  virtual uint32 GetRetType() const = 0;

  virtual uint32 GetParamType(uint32 index) const = 0;
};

struct NoneSignature;

template <typename RetType, typename...ParamTypes> class VariadicsMemSignature;

template <typename RetType, typename...ParamTypes> class VariadicsRawSignature;

class GivenTypeSignature : public Signature {
public:
  GivenTypeSignature();
  GivenTypeSignature(uint32 retType);
  GivenTypeSignature(uint32 retType, uint32 p1);
  GivenTypeSignature(uint32 retType, uint32 p1, uint32 p2);
  GivenTypeSignature(uint32 retType, uint32 p1, uint32 p2, uint32 p3);
  GivenTypeSignature(uint32 retType, uint32 p1, uint32 p2, uint32 p3, uint32 p4);
  GivenTypeSignature(uint32 retType, uint32 p1, uint32 p2, uint32 p3, uint32 p4, uint32 p5);
  GivenTypeSignature(uint32 retType, uint32 p1, uint32 p2, uint32 p3, uint32 p4, uint32 p5, uint32 p6);
  GivenTypeSignature(uint32 retType, uint32 p1, uint32 p2, uint32 p3, uint32 p4, uint32 p5, uint32 p6, uint32 p7);

  uint32 GetParamCount() const OVERRITE;

  uint32 GetRetType() const OVERRITE;

  uint32 GetParamType(uint32 index) const OVERRITE;

private:
  uint32 count_;
  uint32 types_[8];
};

template <typename ... ParamTypes>
Signature *MakeGivenTypeSignature(ParamTypes ... args) {
  return TB_NEW_ARG(GivenTypeSignature, args...);
}

#define TB_IMPLEMENT_SIGNATURE_VARIADICS
 
#define __TB_GEN_GET_PARAM_TYPE_CASE(INDEX) \
  case INDEX: { \
    return GetVariantTypeId<Param##INDEX##Type>(); \
  }
 
#define __TB_PARAM_LIST
#define __TB_PASS_PARAM
#define __TB_GET_PARAM_TYPE_CASES
#define __TB_PARAM_COUNT 0
#define __TB_NO_CASE
#define __TB_VARIADICS_CLASS_PREFIX ZeroParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM
#undef __TB_NO_CASE
 
#define __TB_PARAM_LIST , typename Param1Type
#define __TB_PASS_PARAM , Param1Type
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1)
#define __TB_PARAM_COUNT 1
#define __TB_VARIADICS_CLASS_PREFIX OneParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM
 
#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type
#define __TB_PASS_PARAM , Param1Type, Param2Type
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2)
#define __TB_PARAM_COUNT 2
#define __TB_VARIADICS_CLASS_PREFIX TwoParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM
 
#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type
#define __TB_PASS_PARAM , Param1Type, Param2Type, Param3Type
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3)
#define __TB_PARAM_COUNT 3
#define __TB_VARIADICS_CLASS_PREFIX ThreeParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM
 
#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type
#define __TB_PASS_PARAM , Param1Type, Param2Type, Param3Type, Param4Type
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4)
#define __TB_PARAM_COUNT 4
#define __TB_VARIADICS_CLASS_PREFIX FourParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM
 
#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type, typename Param5Type
#define __TB_PASS_PARAM , Param1Type, Param2Type, Param3Type, Param4Type, Param5Type
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4) __TB_GEN_GET_PARAM_TYPE_CASE(5)
#define __TB_PARAM_COUNT 5
#define __TB_VARIADICS_CLASS_PREFIX FiveParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM
 
#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type, typename Param5Type, typename Param6Type
#define __TB_PASS_PARAM , Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4) __TB_GEN_GET_PARAM_TYPE_CASE(5) __TB_GEN_GET_PARAM_TYPE_CASE(6)
#define __TB_PARAM_COUNT 6
#define __TB_VARIADICS_CLASS_PREFIX SixParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM
 
#define __TB_PARAM_LIST , typename Param1Type, typename Param2Type, typename Param3Type, typename Param4Type, typename Param5Type, typename Param6Type, typename Param7Type
#define __TB_PASS_PARAM , Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type, Param7Type
#define __TB_GET_PARAM_TYPE_CASES __TB_GEN_GET_PARAM_TYPE_CASE(1) __TB_GEN_GET_PARAM_TYPE_CASE(2) __TB_GEN_GET_PARAM_TYPE_CASE(3) __TB_GEN_GET_PARAM_TYPE_CASE(4) __TB_GEN_GET_PARAM_TYPE_CASE(5) __TB_GEN_GET_PARAM_TYPE_CASE(6) __TB_GEN_GET_PARAM_TYPE_CASE(7)
#define __TB_PARAM_COUNT 7
#define __TB_VARIADICS_CLASS_PREFIX SevenParam
#include "signature_impl_variadics.inl"
#undef __TB_VARIADICS_CLASS_PREFIX
#undef __TB_PARAM_LIST
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_GET_PARAM_TYPE_CASES
#undef __TB_PARAM_COUNT
#undef __TB_PASS_PARAM

#undef __TB_GEN_GET_PARAM_TYPE_CASE

#undef TB_IMPLEMENT_SIGNATURE_VARIADICS

TB_NAMESPACE_END

#endif // TB_REFELCTION_SIGNATURE_HPP__
